//
// Created by Asus on 2025/6/1.
//

#include <iostream>
#include <bits/ostream.tcc>
using namespace std;

class Person {
    public:
    Person() {
        cout << "Person constructor" << endl;
    };
    ~Person() {
        cout << "Person destructor" << endl;
    }
};

void demo01() {
    Person p;
}

//1、构造函数分类
// 按照参数分类分为 有参和无参构造   无参又称为默认构造函数
// 按照类型分类分为 普通构造和拷贝构造
class Person2 {
    public:
    //无参（默认）构造函数
    Person2() {
        cout << "无参构造函数!" << endl;
    }
    //有参构造函数
    Person2(int a) {
        age = a;
        cout << "有参构造函数!" << endl;
    }
    //拷贝构造函数
    Person2(const Person2& p) {
        age = p.age;
        cout << "拷贝构造函数!" << endl;
    }
    //析构函数
    ~Person2() {
        cout << "析构函数!" << endl;
    }
public:
    int age;
};

void demo02() {
    Person2 person2;
    Person2 person3;

    //2.1  括号法，常用
    Person2 p1(10);
    //注意1：调用无参构造函数不能加括号，如果加了编译器认为这是一个函数声明
    //Person p2();

    //2.2 显式法
    Person2 p2 = Person2(10);
    Person2 p3 = Person2(p2);
    Person2(10);
    //Person(10)单独写就是匿名对象  当前行结束之后，马上析构

    //2.3 隐式转换法
    Person2 p4 = 10; // Person p4 = Person(10);
    Person2 p5 = p4; // Person p5 = Person(p4);

    //注意2：不能利用 拷贝构造函数 初始化匿名对象 编译器认为是对象声明
    // Person2 p5(p4); // 等价于 Person2 p5 = p4
}

class Person3 {
public:
    Person3() {
        cout << "无参构造函数!" << endl;
        mAge = 0;
    }
    Person3(int age) {
        cout << "有参构造函数!" << endl;
        mAge = age;
    }
    Person3(const Person3& p) {
        cout << "拷贝构造函数!" << endl;
        mAge = p.mAge;
    }
    //析构函数在释放内存之前调用
    ~Person3() {
        cout << "析构函数!" << endl;
    }
public:
    int mAge;
};

//1. 使用一个已经创建完毕的对象来初始化一个新对象
void demo03_1() {
    Person3 man(100); //p对象已经创建完毕
    // Person3 man2 = 100;
    // Person3 man3 = Person3(man);
    // Person3 *man4 = new Person3(man);
    Person3 newman(man);//调用拷贝构造函数
    Person3 man2 = newman; //拷贝构造 等于 Person3 man2 = Person3(newman)
    cout << "man.mAge:" << man.mAge << endl;
    cout << "newman.mAge:" << newman.mAge << endl;
    cout << "man2.mAge:" << man2.mAge << endl;

    Person3 newman3;
    newman3 = man; //不是调用拷贝构造函数，赋值操作
    cout << "newman3.mAge:" << newman3.mAge << endl;
}

//2. 值传递的方式给函数参数传值
//相当于Person p1 = p;
// 拷贝构造函数!
void doWork3_2(Person3 p1) {}
void demo03_2() {
    Person3 p1; // 无参构造函数!
    doWork3_2(p1);
}

//3. 以值方式返回局部对象
Person3 doWork3_3() {
    Person3 p1;
    cout << "&p1:" << &p1 << endl;
    return Person3(p1); // 显式创建副本，阻止NRVO
}

void demo03_3() {
    Person3 p2 = doWork3_3();
    cout << "&p2:" << &p2 << endl;
}

void demo04_1() {
    Person3 p1(18);
    //如果不写拷贝构造，编译器会自动添加拷贝构造，并且做浅拷贝操作
    Person3 p2(p1);
    cout << "p2的年龄为： " << p2.mAge << endl;
}

class Person4 {
    public:
    int age;
};

void demo04_2() {
    Person4 p2;
    p2.age = 10;
    cout << "p2.age:" << p2.age << endl;
    Person4 p3 = p2;
    cout << "p3.age:" << p3.age << endl;
}

void demo04_3() {
    //如果用户提供有参构造，编译器不会提供默认构造，会提供拷贝构造
    Person3 p1; //此时如果用户自己没有提供默认构造，会出错
    Person3 p2(10); //用户提供的有参
    Person3 p3(p2); //此时如果用户没有提供拷贝构造，编译器会提供

    //如果用户提供拷贝构造，编译器不会提供其他构造函数
    Person3 p4; //此时如果用户自己没有提供默认构造，会出错
    Person3 p5(10); //此时如果用户自己没有提供有参，会出错
    Person3 p6(p5); //用户自己提供拷贝构造
}

class Person5 {
public:
    //无参（默认）构造函数
    Person5() {
        cout << "无参构造函数!" << endl;
    }
    //有参构造函数
    Person5(int age ,int height) {

        cout << "有参构造函数!" << endl;

        m_age = age;
        m_height = new int(height);

    }
    //拷贝构造函数
    Person5(const Person5& p) {
        cout << "拷贝构造函数!" << endl;
        //如果不利用深拷贝在堆区创建新内存，会导致浅拷贝带来的重复释放堆区问题
        m_age = p.m_age;
        m_height = new int(*p.m_height);

    }

    //析构函数
    ~Person5() {
        cout << "析构函数!" << endl;
        if (m_height != NULL)
        {
            delete m_height;
        }
    }
public:
    int m_age;
    int* m_height;
};

void demo05() {
    Person5 p1(18, 180);
    Person5 p2(p1);
}

class Person6 {
public:
    // Person6(int a, int b, int c) {
    //     m_a = a;
    //     m_b = b;
    //     m_c = c;
    // }

    Person6(int a, int b, int c) : m_a(a), m_b(b), m_c(c) {}

    void PrintPerson() {
        cout << "m_a:" << m_a << endl;
        cout << "m_b:" << m_b << endl;
        cout << "m_c:" << m_c << endl;
    }

    private:
    int m_a;
    int m_b;
    int m_c;
};

class Phone {
    public:
    Phone(string name) {
        m_PhoneName = name;
        cout << "Phone构造" << endl;
    }

    ~Phone()
    {
        cout << "Phone析构" << endl;
    }

    string m_PhoneName;
};

class Person7 {
    public:
    string m_Name;
    Phone m_Phone;
    Person7(string name, string phone) :m_Name(name), m_Phone(phone) {
        cout << "Person7构造" << endl;
    }
    ~Person7() {cout << "Person7析构" << endl;}
    void playGame() {
        cout << m_Name << " 使用" << m_Phone.m_PhoneName << " 牌手机! " << endl;
    }
};

void demo07() {
    //当类中成员是其他类对象时，我们称该成员为 对象成员
    //构造的顺序是 ：先调用对象成员的构造，再调用本类构造
    //析构顺序与构造相反
    Person7 p("张三" , "苹果X");
    p.playGame();
}

class Person8 {
    public:
    static int m_A; //静态成员变量
    //静态成员变量特点：
    //1 在编译阶段分配内存
    //2 类内声明，类外初始化
    //3 所有对象共享同一份数据

private:
    static int m_B; //静态成员变量也是有访问权限的
};

int Person8::m_A = 10;
int Person8::m_B = 10;

void demo08() {
    //静态成员变量两种访问方式
    //1、通过对象
    Person8 p1;
    p1.m_A = 100;
    cout << "p1.m_A = " << p1.m_A << endl;

    Person8 p2;
    p2.m_A = 200;
    cout << "p1.m_A = " << p1.m_A << endl; //共享同一份数据
    cout << "p2.m_A = " << p2.m_A << endl;

    //2、通过类名
    cout << "m_A = " << Person8::m_A << endl;
    // cout << "m_B = " << Person::m_B << endl; //私有权限访问不到
}

class Person9 {
public:
    static int m_A; //静态成员变量
    int m_B; //
    //静态成员函数特点：
    //1 程序共享一个函数
    //2 静态成员函数只能访问静态成员变量
    static void func()
    {
        cout << "func调用" << endl;
        m_A = 100;
        //m_B = 100; //错误，不可以访问非静态成员变量
    }
private:
    //静态成员函数也是有访问权限的
    static void func2()
    {
        cout << "func2调用" << endl;
    }
};

int Person9::m_A = 10;

void demo09() {
    //静态成员变量两种访问方式
    //1、通过对象
    Person9 p1;
    p1.func();

    //2、通过类名
    Person9::func();
    //Person::func2(); //私有权限访问不到
}

int main() {
    // demo01();
    // demo02();
    // demo03_1();
    // demo03_2();
    // demo03_3();
    // demo04_1();
    // demo04_2();
    // demo05();
    // demo07();
    // demo08();
    demo09();
    return 0;
}